/**
 * 
 */
package org.statewalker.core.server;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.LinkedBlockingQueue;

import org.statewalker.core.Core;
import org.statewalker.core.ErrorEvent;
import org.statewalker.core.IEvent;
import org.statewalker.core.IProcessContext;
import org.statewalker.core.IState.ICallback;

/**
 * @author kotelnikov
 */
public class ServerCore extends Core implements Runnable {

    private Throwable fError;

    private boolean fStopped;

    public ServerCore(int poolSize) {
        super(new LinkedBlockingQueue<Runnable>(), new ThreadedStateExecutor(
            poolSize));
    }

    private void doRun() {
        try {
            while (!isStopped()) {
                if (!tick()) {
                    Thread.sleep(10);
                }
            }
        } catch (Throwable e) {
            fError = e;
        }
    }

    @Override
    public ThreadedStateExecutor getDefaultStateExecutor() {
        return (ThreadedStateExecutor) super.getDefaultStateExecutor();
    }

    public Throwable getError() {
        return fError;
    }

    protected boolean isStopped() {
        return fStopped;
    }

    public void run() {
        doRun();
    }

    public void runInThread(boolean block)
        throws InterruptedException,
        BrokenBarrierException {
        if (block) {
            final CyclicBarrier barrier = new CyclicBarrier(2);
            new Thread() {
                @Override
                public void run() {
                    try {
                        doRun();
                    } finally {
                        try {
                            barrier.await();
                        } catch (RuntimeException e) {
                            throw e;
                        } catch (Exception e) {
                        }
                    }
                }
            }.start();
            barrier.await();
        } else {
            new Thread(this).start();
        }
    }

    public void runProcess(String processName, IProcessContext context)
        throws Exception {
        final Throwable[] error = { null };
        final CyclicBarrier barrier = new CyclicBarrier(2);
        startProcess(processName, context, new ICallback() {
            public void finish(IEvent event) {
                if (event instanceof ErrorEvent) {
                    error[0] = ((ErrorEvent) event).error;
                }
                try {
                    barrier.await();
                } catch (Throwable t) {
                    error[0] = t;
                }
            }
        });
        barrier.await();
        if (error[0] instanceof Error) {
            throw (Error) error[0];
        } else if (error[0] instanceof Exception) {
            throw (Exception) error[0];
        }
    }

    public void stop() {
        fStopped = true;
    }

}